package com.example.sample.activity;

import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

import com.example.app.BaseActivity;
import com.example.sample.R;
import com.example.sample.control.NoSSLv3Factory;
import com.example.sample.control.TlsSniSocketFactory;
import com.example.sample.util.ExceptionUtil;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

/**
 * Created by LiangYu on 2017/7/14.
 */
public class HttpRequestActivity extends BaseActivity {

    private EditText urlEditText;
    private EditText inputEditText;
    private TextView outputTextView;
    private TextView certTextView;
    private Button requestButton;
    private Handler handler;
    private ExecutorService executorService = Executors.newFixedThreadPool(100);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_http_request);
        urlEditText = (EditText) findViewById(R.id.url);
        inputEditText = (EditText) findViewById(R.id.input);
        outputTextView = (TextView) findViewById(R.id.output);
        certTextView = (TextView) findViewById(R.id.cert);
        requestButton = (Button)findViewById(R.id.request);
        requestButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                for (int i = 0; i < 1 ; i++){
                    log("========================" + i++);
                    asyncSend();
                }
            }
        });

        String input = "{\"clientInfo\":{\"channelType\":20,\"clientIp\":\"10.1.94.96\",\"location\":\"\",\"networkProvider\":0,\"networkType\":1},\"token\":\"3ec6a04b1828e4f67941f2e41cad2d7bIiPjI8cX\",\"userId\":\"1261\"}";
        inputEditText.setText(input);

        String url = "https://msglb.91160.com";
        //String url = "https://120.132.241.135";
        //String url = "https://doctorand.91160.com";
        //String url = "https://msglb.91160.com/msg/broker/get";
        urlEditText.setText(url);

        handler = new Handler(Looper.getMainLooper());
    }

    private void asyncSend(){
        new AsyncTask<Void, Void, String>(){

            private String url = urlEditText.getText().toString();
            private String input = inputEditText.getText().toString();

            @Override
            protected String doInBackground(Void[] params) {
                return send(url, input);
            }

            @Override
            protected void onPostExecute(String o) {
                super.onPostExecute(o);
                outputTextView.setText(o);
            }
        }.executeOnExecutor(executorService);
    }

    private String send(String url, String input){
        String result = "";
        HttpURLConnection conn = null;
        try {
            // 输入参数
            log("request data >> url = " + url + " input = " + input);

            conn = createConnection(url);
            conn.connect();

            PrintWriter printWriter = new PrintWriter(conn.getOutputStream());
            printWriter.write(input);
            printWriter.flush();
            printWriter.close();

            int responseCode = conn.getResponseCode();
            String responseMessage = conn.getResponseMessage();
            log("responseCode = " + responseCode + " responseMessage = " + responseMessage);

            // 输出参数
            String output = "";
            try{
                InputStream is = conn.getInputStream();
                if (is != null){
                    output = convertStreamToString(is);
                }
            }catch (Exception e){
            }

            log("response << code = " + responseCode
                    + " message = " + responseMessage
                    + " data = " + output);

            result = output;
        } catch (Exception e) {
            log(ExceptionUtil.getErrorInfoFromException(e));
        } finally {
            try{
                conn.disconnect();
            }catch (Exception e){
            }
        }
        return result;
    }

    private void log(String text){
        System.out.println(TAG + ">> " +text);
    }

    public static String convertStreamToString(InputStream is) {
        /*
          * To convert the InputStream to String we use the BufferedReader.readLine()
          * method. We iterate until the BufferedReader return null which means
          * there's no more data to read. Each line will appended to a StringBuilder
          * and returned as String.
          */
        BufferedReader reader = new BufferedReader(new InputStreamReader(is));
        StringBuilder sb = new StringBuilder();

        String line = null;
        try {
            while ((line = reader.readLine()) != null) {
                sb.append(line + "\n");
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                is.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        return sb.toString();
    }

    private SSLSocketFactory getSslSocketFactory(){
        X509TrustManager x509m = new X509TrustManager() {

            @Override
            public X509Certificate[] getAcceptedIssuers() {
                return null;
            }

            @Override
            public void checkServerTrusted(X509Certificate[] chain,
                                           String authType) throws CertificateException {
                try{
                    chain[0].checkValidity();
                    final String traceText = getCertTraceString(chain[0]);
                    log(traceText);
                    handler.post(new Runnable() {
                        @Override
                        public void run() {
                            certTextView.setText(traceText);
                        }
                    });
                }catch (Exception e){
                    throw new CertificateException("Certificate not valid or trusted.");
                }finally {
                    //throw new CertificateException("Certificate not valid or trusted.");
                }
            }

            @Override
            public void checkClientTrusted(X509Certificate[] chain,
                                           String authType) throws CertificateException {
            }

            private String getCertTraceString(X509Certificate cert){
                StringBuffer stringBuffer = new StringBuffer();
                stringBuffer.append("\n版本 " + cert.getVersion());
                stringBuffer.append("\n签发者唯一标识 " + cert.getIssuerUniqueID());
                stringBuffer.append("\n签名算法名 " + cert.getSigAlgName());
                stringBuffer.append("\n签名算法OID字符串 " + cert.getSigAlgOID());
                stringBuffer.append("\n基本扩展长度 " + cert.getBasicConstraints());
                //stringBuffer.append("getIssuerDN " + cert.getIssuerDN());
                stringBuffer.append("\n签发者详细信息 " + cert.getIssuerX500Principal());
                stringBuffer.append("\n秘钥用法 " + cert.getKeyUsage());
                stringBuffer.append("\n截止日期 " + cert.getNotAfter());
                stringBuffer.append("\n起始日期 " + cert.getNotBefore());
                stringBuffer.append("\n序列号 " + cert.getSerialNumber());
                stringBuffer.append("\n签名算法参数 " + cert.getSigAlgParams());
                stringBuffer.append("\n签名 " + cert.getSignature());

                stringBuffer.append("\n被签发者唯一标识 " + cert.getSubjectUniqueID());
                //stringBuffer.append("getSubjectDN " + cert.getSubjectDN());
                stringBuffer.append("\n被签发者详细信息 " +  cert.getSubjectX500Principal());

                try{
                    stringBuffer.append("\n证书信息 " + cert.getTBSCertificate());
                    stringBuffer.append("\n扩展秘钥用法 " + cert.getExtendedKeyUsage());
                    stringBuffer.append("\n签发者可选名 " + cert.getIssuerAlternativeNames());
                    stringBuffer.append("\n被签发者可选名 " + cert.getSubjectAlternativeNames());
                }catch (Exception e){
                }
                return stringBuffer.toString();
            }
        };

        X509TrustManager x509TrustManager = new X509TrustManager(){

            @Override
            public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {

            }

            @Override
            public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {

            }

            @Override
            public X509Certificate[] getAcceptedIssuers() {
                return new X509Certificate[0];
            }
        };
        SSLContext ctx = null;
        try {
            ctx = SSLContext.getInstance("TLSv1");
            ctx.init(null, null, null);
        }catch (Exception e) {
            log(ExceptionUtil.getErrorInfoFromException(e));
        }

        SSLSocketFactory sslSockFactory = ctx.getSocketFactory();
        return sslSockFactory;
    }

    public SSLSocketFactory getSSLSocketFactory(){
        X509TrustManager x509TrustManager = new X509TrustManager(){

            @Override
            public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {

            }

            @Override
            public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {

            }

            @Override
            public X509Certificate[] getAcceptedIssuers() {
                return new X509Certificate[0];
            }
        };
        SSLContext ctx = null;
        try {
            ctx = SSLContext.getInstance("TLSv1");
            ctx.init(null, new TrustManager[]{x509TrustManager}, null);
            ctx.init(null, null, null);
        }catch (Exception e) {
            log(ExceptionUtil.getErrorInfoFromException(e));
        }

        SSLSocketFactory sslSockFactory = ctx.getSocketFactory();
        return sslSockFactory;
    }

    private HttpURLConnection createConnection(String url){
        HttpURLConnection conn = null;
        try{
            URL curUrl = new URL(url);
            conn = (HttpURLConnection)curUrl.openConnection();
            if (conn instanceof HttpsURLConnection){
                HttpsURLConnection httpsURLConnection = (HttpsURLConnection)conn;
                //httpsURLConnection.setRequestProperty("Host", "doctorand.91160.com");
                httpsURLConnection.setSSLSocketFactory(new NoSSLv3Factory(getSslSocketFactory()));
                //httpsURLConnection.setSSLSocketFactory(new TlsSniSocketFactory(httpsURLConnection));
                httpsURLConnection.setHostnameVerifier(new HostnameVerifier() {
                    @Override
                    public boolean verify(String hostname, SSLSession session) {
                        return true;
                    }
                });
                /*httpsURLConnection.setHostnameVerifier(new HostnameVerifier() {
                    @Override
                    public boolean verify(String hostname, SSLSession session) {
                        if ("msglb.91160.com".equals(hostname)){

                        }
                        return false;
                    }
                });*/
            }
            conn.setRequestProperty("content-type", "application/json");
            conn.setRequestMethod("POST");
            conn.setConnectTimeout(10000);
            conn.setReadTimeout(2000);
            conn.setDoOutput(true);
            conn.setDoInput(true);
        }catch (Exception e){
            log(ExceptionUtil.getErrorInfoFromException(e));
        }
        return conn;

    }
}
